tree grammar GrammarEvaluator;

options {
  language = Java;
  tokenVocab = BasicArithmeticEqu;
  ASTLabelType = CommonTree;
}

@header{
	package arith;
	import java.util.Map;
	import java.util.HashMap;
	import java.util.Random;
}

@members {
	public Map<String, Double> variables = new HashMap<String, Double>();
	BuildEquation build = new BuildEquation();
}

problem returns [Problem prob]
	: op = operation {prob = op;}
	;

operation returns [Problem prob]
	:	ADD {prob = build.makeEqu(0, 0);}
	|	SUB {prob = build.makeEqu(1, 0);}
	|	MULT {prob = build.makeEqu(2, 0);}
	|	DIV {prob = build.makeEqu(3, 0);}
	|	FRACADD {prob = build.makeEqu(4, 0);}
	|	FRACSUB	{prob = build.makeEqu(5, 0);}
	|	FRACMULT {prob = build.makeEqu(6, 0);}
	| FRACDIV {prob = build.makeEqu(7, 0);}
	| EXPADD {prob = build.makeEqu(8, 0);}
	| EXPSUB {prob = build.makeEqu(9, 0);}
	| EXPMULT {prob = build.makeEqu(10, 0);}
	| EXPDIV {prob = build.makeEqu(11, 0);}
	;

evaluator returns [Output output]
	: n=expression EOF {output = new Output(n);}
	|	f=fraction EOF {output = new Output(f);}
	|	e=exponent EOF {output = new Output(e);}
	|	fac=factor EOF {output = new Output(fac);}
	| prop=property EOF {output = new Output(prop);}
	;

property returns [Properties prop]
	: ASSOC {
			Random randomGenerator = new Random();
			prop = new Properties(randomGenerator.nextInt(2));
		}
	| DIST{
			prop = new Properties(2);
		}
	;

factor returns [Factoring fac]
	: FACTOR {
			Random random = new Random();
			int n = random.nextInt(99) + 1;
			fac = new Factoring(n);
		}
	| GCF {
			Random random = new Random();
			int n1 = random.nextInt(99) + 1;
			int n2 = random.nextInt(99) + 1;
			fac = new Factoring(n1, n2, 0);
		}
	| LCM {
			Random random = new Random();
			int n1 = random.nextInt(99) + 1;
			int n2 = random.nextInt(99) + 1;
			fac = new Factoring(n1, n2, 1);
		}
	;

expression returns [Numbers result]
	:	^('+' op1=expression op2=expression) {result = op1.add(op2);}
	| ^('+' op3=exponent op4=exponent) {result = op3.add(op4);}
	|	^('-' op1=expression op2=expression) {result = op1.sub(op2);}
	| ^('-' op3=exponent op4=exponent) {result = op3.sub(op4);}
	|	^('*' op1=expression op2=expression) {result = op1.mult(op2);}
	|	^('/' op1=expression op2=expression) {result = op1.div(op2);}
	/*|	^('mod' op1=expression op2=expression) {result = new Numbers(op1.number \% op2.number);}*/
	|	^(NEGATION e=expression) {result = e.mult(new Numbers(-1, ""));}
	|	IDENT {
			if(variables.containsKey($IDENT.text)){
				result = new Numbers(variables.get($IDENT.text), "");
			}else{
				Random randomGenerator = new Random();
				double temp = randomGenerator.nextInt(9) + 1;
				result = new Numbers(temp, "");
				variables.put($IDENT.text, temp);
			}
		}
	| INTEGER {result = new Numbers(Integer.parseInt($INTEGER.text), "");}
	;

fraction returns [Fraction frac]
	:	^('plus' op3=fraction op4=fraction) {frac = op3.add(op4);}
	|	^('minus' op1=fraction op2=fraction) {frac = op1.sub(op2);}
	|	^('times' op1=fraction op2=fraction) {frac = op1.mult(op2);}
	|	^('divides' op1=fraction op2=fraction) {frac = op1.div(op2);}
	|	FRAC	{
			Random randomGenerator = new Random();
			int temp1 = randomGenerator.nextInt(9) + 1;
			int temp2 = randomGenerator.nextInt(9) + 1;
			frac = new Fraction(temp1, temp2, "");
		}
	;
	
exponent returns [Exponent exp]
	: ^('eMult' op1=exponent op2=exponent) {exp = op1.mult(op2);}
	| ^('eDiv' op1=exponent op2=exponent) {exp = op1.div(op2);}
	|	EXP	{
			Random randomGenerator = new Random();
			int temp1 = randomGenerator.nextInt(9) + 1;
			int temp2 = randomGenerator.nextInt(9) + 1;
			exp = new Exponent(temp1, temp2, "");
		}
	;